package org.muninn.niagara.bql;

import javax.baja.collection.BIList;
import javax.baja.control.BBooleanWritable;
import javax.baja.control.BControlPoint;
import javax.baja.control.BEnumWritable;
import javax.baja.control.BNumericWritable;
import javax.baja.control.BStringWritable;
import javax.baja.control.util.BBooleanOverride;
import javax.baja.control.util.BEnumOverride;
import javax.baja.control.util.BNumericOverride;
import javax.baja.control.util.BStringOverride;
import javax.baja.naming.BOrd;
import javax.baja.sys.Action;
import javax.baja.sys.BBoolean;
import javax.baja.sys.BComponent;
import javax.baja.sys.BDouble;
import javax.baja.sys.BDynamicEnum;
import javax.baja.sys.BIcon;
import javax.baja.sys.BString;
import javax.baja.sys.BValue;
import javax.baja.sys.Flags;
import javax.baja.sys.Property;
import javax.baja.sys.Sys;
import javax.baja.sys.Type;

public class BPointSync extends BComponent
{
  /** Path to the location of the point*/
  public static final Property pointPath = newProperty(0, BOrd.make("station:|slot:/Drivers"));
  public void setPointPath(BOrd v) { set("pointPath", v); }
  public BOrd getPointPath() { return (BOrd) get("pointPath"); }
  
  /** Name of the point to be synced */
  public static final Property pointName = newProperty(Flags.SUMMARY, "");
  public void setPointName(String v) { setString(pointName, v, null); }
  public String getPointName() { return getString(pointName); }

  /** Value to be synced across point list */
  public static final Property syncValue = newProperty(Flags.SUMMARY, "");
  public void setSyncValue(String v) { setString(syncValue, v, null); }
  public String getSyncValue() { return getString(syncValue); }
  
  /** Whether or not to include wildcard characters and use 'like' instead of '=' */
  public static final Property exactMatch = newProperty(0, true);
  public void setExactMatch(boolean v) { setBoolean(exactMatch, v, null); }
  public boolean getExactMatch() { return getBoolean(exactMatch); }
  
  /** Places point in emergency override **/
  public static final Action emergencyOverride = newAction(0, null);
  public void emergencyOverride() { invoke(emergencyOverride, null); }
  public void doEmergencyOverride() throws Exception { setup(0); }
  
  /** Places point in emergency auto **/
  public static final Action emergencyAuto = newAction(0, null);
  public void emergencyAuto() { invoke(emergencyAuto, null); }
  public void doEmergencyAuto() throws Exception { setup(1); }
  
  /** Places point in override **/
  public static final Action override = newAction(256, null);
  public void override() { invoke(override, null); }
  public void doOverride() throws Exception { setup(2); }

  /** Places point in auto **/
  public static final Action auto = newAction(256, null);
  public void auto() { invoke(auto, null); }
  public void doAuto() throws Exception { setup(3); }
  
  /** Executes set command on point **/
  public static final Action set = newAction(256, null);
  public void set() { invoke(set, null); }
  public void doSet() throws Exception { setup(4); }

  private static String path;
  private static String point;
  private static String sync;
  private static boolean match;
  private BControlPoint[] points;
  
  private void setup(int com)
  {
    path = getPointPath().toString();
    point = getPointName();
    sync = getSyncValue();
    match = getExactMatch();

    BIList rawPoints;
    if (match)
      rawPoints = (BIList) BOrd.make(path + "|bql:select * from control:ControlPoint where displayName = '" + point + "'").resolve().get();
    else
      rawPoints = (BIList) BOrd.make(path + "|bql:select * from control:ControlPoint where displayName like '*" + point + "*'").resolve().get();
    
    if (rawPoints.size() == -1) return;
    
    points = new BControlPoint[rawPoints.size()];
    points = (BControlPoint[]) rawPoints.list(points);
    
    for (int i = 0; i < points.length; i++)
      executeCom(points[i], com);
  }
  
  private void executeCom(BControlPoint point, int com)
  {
    if (point.getType().toString().toLowerCase().equals("control:numericwritable"))
    {
      BNumericWritable temp = (BNumericWritable) point;
      BValue writeVal = BDouble.make(Double.parseDouble(sync));
      switch (com)
      {
        case 0:
          temp.emergencyOverride((BDouble) writeVal);
          break;
          
        case 1:
          temp.emergencyAuto();
          break;
          
        case 2:
          temp.override(new BNumericOverride(Double.parseDouble(sync)));
          break;
          
        case 3:
          temp.auto();
          break;
          
        case 4:
          temp.set((BDouble) writeVal);
          break;
      }
    }
    
    else if (point.getType().toString().toLowerCase().equals("control:booleanwritable"))
    {
      BBooleanWritable temp = (BBooleanWritable) point;
      BValue writeVal = BBoolean.make(sync.equals("true"));
      switch (com)
      {
        case 0:
          if (sync.equals("true"))
            temp.emergencyActive();
          else
            temp.emergencyInactive();
          break;
        
        case 1:
          temp.emergencyAuto();
          break;
        
        case 2:
          if (sync.equals("true"))
            temp.active(new BBooleanOverride(true));
          else
            temp.inactive(new BBooleanOverride(false));
          break;
        
        case 3:
          temp.auto();
          break;
          
        case 4:
          temp.set((BBoolean) writeVal);
          break;
      }
    }
    
    else if (point.getType().toString().toLowerCase().equals("control:enumwritable"))
    {
      BEnumWritable temp = (BEnumWritable) point;
      BValue writeVal = BDynamicEnum.make(Integer.parseInt(sync));
      switch (com)
      {
        case 0:
          temp.emergencyOverride((BDynamicEnum) writeVal);
          break;
        
        case 1:
          temp.emergencyAuto();
          break;
        
        case 2:
          temp.override(new BEnumOverride((BDynamicEnum) writeVal));
          break;
        
        case 3:
          temp.auto();
          break;

        case 4:
          temp.set((BDynamicEnum) writeVal);
          break;
      }
    }
    
    else if (point.getType().toString().toLowerCase().equals("control:stringwritable"))
    {
      BStringWritable temp = (BStringWritable) point;
      BValue writeVal = BString.make(sync);
      switch (com)
      {
        case 0:
          temp.emergencyOverride((BString) writeVal);
          break;
        
        case 1:
          temp.emergencyAuto();
          break;
        
        case 2:
          temp.override(new BStringOverride(sync));
          break;
        
        case 3:
          temp.auto();
          break;
          
        case 4:
          temp.set((BString) writeVal);
          break;
      }
    }
    
    else return;
  }
  
  public BIcon getIcon() { return icon; }
  private static final BIcon icon = BIcon.make("local:|module://muninn/org/muninn/niagara/graphics/MuninnGroup.PNG");

  public static final Type TYPE = Sys.loadType(BPointSync.class);
  public Type getType() { return TYPE; }
}
